home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v9n03.arc / CFCOMP.ASM < prev    next >
Assembly Source File  |  1990-01-12  |  75KB  |  1,208 lines

  1.          PAGE  60,132
  2.          TITLE CFcomp - CHKfile file compare utility
  3. ;        SUBTTL  General program description and use of common storage
  4. ;-----------------------------------------------------------------------------;
  5. ;        CFCOMP - Compare output files created by CHKfile                     ;
  6. ;-----------------------------------------------------------------------------;
  7. ;   CFCOMP 1.0 ■ PCDATA TOOLKIT Copyright (c) 1990 Ziff Communications Co.    ;
  8. ;                   PC Magazine ■ Wolfgang Stiller                            ;
  9. ;                                                                             ;
  10. ;-----------------------------------------------------------------------------;
  11. ;
  12. ; Purpose:                                                                    ;
  13. ; CFCOMP does a high speed compare of redirected output (report) files        ;
  14. ; captured from CHKfile.  CFCOMP then displays which files have been          ;
  15. ; changed, deleted or added between the creation of the OLD and NEW           ;
  16. ; report files.                                                               ;
  17. ; ----------------------------------------------------------------------------;
  18. ;Format:                                                                      ;
  19. ;                                                                             ;
  20. ;CFCOMP OLDfile NEWfile  [/C] [/O] [/P]                                       ;
  21. ;                                                                             ;
  22. ;      OLDfile and NEWfile are CHKFILE.COM created report files.              ;
  23. ;      "/C"      Changes only - reports and checks only for changed files     ;
  24. ;                and ignores additions or deletions from file list.           ;
  25. ;      "/O"      Only use check fields and file size for comparison. DOS time ;
  26. ;                and date stamps are not used in comparing.                   ;
  27. ;      "/P"      Pauses after each page of output if non-matches are detected.;
  28. ; ----------------------------------------------------------------------------;
  29. ;Remarks:                                                                     ;
  30. ; CFCOMP utilizes a high speed compare algorithm tailored specifically        ;
  31. ; to comparing data produced by CHKfile.  It will work even if the            ;
  32. ; directories have been sorted in a different order.  The order of the        ;
  33. ; files in the NEW and OLD files is completely independent. If the order      ;
  34. ; is the same, (which is usually the case) CFCOMP runs the fastest. If        ;
  35. ; both files were created using the /T option on CHKfile, then CFCOMP         ;
  36. ; will report whether the totals match.  If the totals match, yet CFCOMP      ;
  37. ; reports additions and deletions, this usually indicates that files          ;
  38. ; were effectively renamed. CFCOMP writes to DOS standard output, so          ;
  39. ; that its output may be redirected to a file. "CFCOMP A B >OUT" will         ;
  40. ; compare old file A and new file B with any differences reported on          ;
  41. ; file OUT.                                                                   ;
  42. ;                                                                             ;
  43. ; If the OLDfile is not found, CFCOMP will report this fact and then          ;
  44. ; continue executing, treating OLDfile as if it were an empty file.           ;
  45. ;                                                                             ;
  46. ; The individual report (input) files may not be larger than 65,536           ;
  47. ; bytes.  This size allows up to 1260 file entries in each report file.       ;
  48. ; To compare this many entries in each file, CFCOMP requires that at          ;
  49. ; least 133,000 bytes of memory are free. CFCOMP will automatically           ;
  50. ; adjust its memory allocation to use whatever memory is available. For       ;
  51. ; each 1000 less bytes of free memory, 10 fewer file entries can be           ;
  52. ; supported.                                                                  ;
  53. ;                                                                             ;
  54. ; All serious error conditions (such as a corrupted or invalid report         ;
  55. ; file) will result in an error message accompanied by a beep, a prompt       ;
  56. ; and a wait for a key press.                                                 ;
  57. ;                                                                             ;
  58. ; CFCOMP will return the following DOS ERRORLEVELs (decimal):                 ;
  59. ;  128 - indicates control card syntax error                                  ;
  60. ;   20 - indicates file open or other I/O error on one of the files           ;
  61. ;   16 - indicates file(s) of invalid type for CFCOMP or file too large       ;
  62. ;        (64K or larger is too large - this is more than 1260 lines)          ;
  63. ;   12 - indicates file(s) have been changed                                  ;
  64. ;    8 - indicates file(s) added and/or deleted but no files changed          ;
  65. ;    4 - indicates file(s) have probably been renamed rather than actually    ;
  66. ;        changed or deleted, since the "TOTAL==>" lines match but the files   ;
  67. ;        themselves did not.                                                  ;
  68. ;    0 - files match exactly                                                  ;
  69. ; --------------------------------------------------------------------------  ;
  70. ;Sample output:                                                               ;
  71. ;                                                                             ;
  72. ;CFCOMP 1.0 [(c) 1989 W. Stiller] comparing in directory: \ASM\EXAMPLES       ;
  73. ;          File Name + Check Check  File    Update   Update                   ;
  74. ;          Extension:  Val1: Val2:  Size:   Date:    Time:                    ;
  75. ;          ----------   ---- ----   -----   ------   ------                   ;
  76. ;Chgd: OLD:SDOC.BAK     BC37 2709     61A6 02/09/89 00:07:54                  ;
  77. ;      NEW:SDOC.BAK     A6B4 A64F     6769 02/11/89 23:55:02                  ;
  78. ;Chgd: OLD:SDOC         BC37 2709     61A6 02/09/89 00:13:48                  ;
  79. ;      NEW:SDOC         BC37 2709     61A6 02/12/89 00:07:54                  ;
  80. ;Deleted-->OUT          1E4A 4FD5       65 02/12/89 00:10:30                  ;
  81. ;NEW Fil-->NEWOUT.TXT   1E4A 4FD5       65 02/12/89 00:10:30                  ;
  82. ;NEW Fil-->TESTDIR      Dir.               02/11/89 00:07:48                  ;
  83. ;File totals unequal                                                          ;
  84. ;                                                                             ;
  85. ;Notes: CFCOMP displays which directory it is in, when doing the compare.     ;
  86. ;       In this case, it is in directory \ASM\EXAMPLES.  Files SDOC and       ;
  87. ;       SDOC.BAK have both changed. Even though file OUT has apparently       ;
  88. ;       been deleted and file NEWOUT.TXT has been added, it is obvious        ;
  89. ;       that file OUT has merely been renamed since the check values and      ;
  90. ;       file sizes match. TESTDIR is the name of a directory which has        ;
  91. ;       been added.                                                           ;
  92. ; ----------------------------------------------------------------------------;
  93.  
  94. ;---------------------------------------------------------------;
  95. ; Constants:                                                    ;
  96. ;---------------------------------------------------------------;
  97. BOX               EQU    254              ;Small box character code
  98. CR                EQU    0Dh
  99. LF                EQU    0Ah
  100. CRLF              EQU    0A0Dh            ;Carriage return line feed.
  101. DSP_Key_len       EQU    12               ;Length of the key part of DSP record
  102. DSP_Rec_len       EQU    51               ;Length of the DSP (Display) record
  103.  
  104.  
  105. CSEG    SEGMENT
  106.         ASSUME  CS:CSEG, DS:CSEG, ES:Nothing, SS:CSEG
  107.         SUBTTL  Main program
  108. ;******************************************************************************;
  109. ;**   Main program begins here -CFCOMP-                                      **;
  110. ;******************************************************************************;
  111.         ORG     100H                      ; THIS IS A COM TYPE PROGRAM
  112. CFCOMP:
  113.         CALL    Parse_parms_Open_Files    ;Parse cmdline paramters + open files
  114.  
  115.         MOV     BX,offset Buffer_Area+200 ;locate stack down in prog storage
  116.         MOV     SP,BX                     ;Stack of 200 bytes
  117.  
  118.         CALL    Allocate_Memory           ;Allocate memory for file buffers
  119.                                           ;and release other unused memory.
  120.                                           ;ES will point to start of alloc mem
  121.  
  122.         CALL    Read_and_Validate_Files   ;Validate that both files are
  123.                                           ;readable and of right type to read
  124.                                           ;DS is now addressing DATA SEG (DS=CS)
  125.         XOR     BX,BX                     ;Zero highest error level variable(BL)
  126.         MOV     BH,Page_mode              ;Load line counter + pagemode flag
  127.                                           ;   =FFh for no paging
  128.         CALL    Compare_Files             ;Compare OLD file with NEW file and
  129.                                           ; determine changed or deleted recs
  130.         CALL    Scan_for_Additions        ;Look for records left on NEW file
  131.         CALL    Compare_totals            ;Check if total===> lines match
  132.         CMP     BH,0FFh                   ;See if page mode is off (= FFh)
  133.         JE      Normal_termination        ;   IF turned off, skip page control
  134.         OR      BL,BL                     ;See if changes detected (BL not = 0)
  135.         JE      Normal_termination        ;   If no changes, then terminate
  136.         CALL    Page_Wait                 ;   otherwise pause for user to read
  137.                                           ;     the display.
  138. Normal_termination:
  139.         MOV     AL,BL                     ;Load error level for termination
  140.         MOV     AH,4Ch                    ;   terminate
  141.         INT     21h
  142.  
  143. ;---------------------------------------------------------------------------;
  144. ; Compare files   - will compare OLD and NEW file (51 char DISPLAY records) ;
  145. ;---------------------------------------------------------------------------;
  146. ; Register conventions:                                                     ;
  147. ;    DS=Segment register for OLD SEG      ES=NEW report file segment        ;
  148. ;    SI=offset of current OLD rec         DI=offset of current NEW rec      ;
  149. ;    CX=number of OLD recs left to proc.  BP=offset of last NEW rec         ;
  150. ;    BL=highest code for DOS errorlevel   BH=line counter (for /P option)   ;
  151. ;---------------------------------------------------------------------------;
  152. ; Entry:                                                                    ;
  153. ;  Both files have been read into  buffers and validated                    ;
  154. ;  DS is segment register for DATA(=CS); ES is segment regst for NEW file.  ;
  155. ;  BP is offset 1st rec on NEW file                                         ;
  156. ; Exit:                                                                     ;
  157. ;   All matched NEW file entries have 1st byte of filename zeroed.          ;
  158. ;   Reports have been written to Std output, on discrepancies so far.       ;
  159. ;   BL = 12 if changes, =8 if added/deleted files, and =0 for no changes    ;
  160. ;---------------------------------------------------------------------------;
  161. Compare_early_exit:
  162.         RET
  163. Compare_Files:                            ;<==== Enter here
  164.         MOV     DI,BP                     ;1st record address of NEW file
  165.         MOV     SI,OLD_File_Start         ;1st record address of OLD file
  166.         MOV     CX,OLD_Rec_count          ;number of records on OLD file
  167.         JCXZ    Compare_early_exit        ;If no files in OLD directory: EXIT
  168.         MOV     BP,NEW_End_Of_File        ;Offset after last rec on NEW file
  169.         MOV     AX,ES                     ;NEW file SEGment
  170.         SUB     AX,File_Size_PARAs        ;Back down from NEW file to OLD file
  171.         MOV     DS,AX                     ;DS = SEG reg for OLD file
  172.         SUB     DI,DSP_Rec_Len            ;Point to -1 record on NEW file
  173.         SUB     SI,DSP_Rec_Len            ;Point to record -1 on OLD file
  174.  
  175. Compare_Next:                             ;Main compare loop - Get next NEW+OLD
  176.         ADD     DI,DSP_Rec_Len            ;Advance to next NEW record
  177. Check_Next_OLD_REC:                       ;Secondary compare loop: next OLD rec
  178.         ADD     SI,DSP_rec_len            ;Advance to next OLD rec
  179.         CMP     DI,BP                     ;Compare offset of this NEW rec + EOF
  180.         JB      Compare_Keys              ;  If we are not past EOF on this rec
  181.         CALL    Display_Deleted_MSG       ;  Else remaining old recs are deletd
  182.         LOOP    Check_Next_OLD_REC        ;Continue reporting deleted old recs
  183.         RET                               ;All done with main file compare
  184.  
  185. Compare_Keys:
  186. ; Compare File keys  (1st 12 characters of each record)
  187.         MOV     DX,CX                     ;Save a copy of CX (# of old recs)
  188.         MOV     CX,DSP_Key_Len/2          ;Compare 12 character key (6 words)
  189.         PUSH    DI                        ;Save current NEW rec loc
  190.         PUSH    SI                        ;Save current OLD rec loc
  191.         REPE    CMPSW                     ;Do compare
  192.         JNE     Find_Matching_NEW_Rec     ;if not =, Scan NEW file for a match
  193.  
  194. ;       Now compare the actual records (keys already match):
  195. ;       ***Warning*** the length field of following instr may be patched by /O
  196. PATCH1: MOV     CX,18                     ;Check remainder of record (18 words)
  197.         INC     DI                        ;Skip checking next blank separator
  198.         INC     SI                        ;Skip checking next blank separator
  199.         REPE    CMPSW                     ;Do compare
  200.         POP     SI                        ;Point back to start of this OLD rec
  201.         POP     DI                        ;Point back to start of this NEW rec
  202.         JE      Good_compare              ;If the records match
  203.         CALL    Display_changed_MSG       ;Report detection of changed record
  204. Good_compare:
  205. ;       Now zero out the 1st byte of the matched NEW file record:
  206.         XOR     AX,AX                     ;Zeros to store on key of record
  207.         STOSB                             ;Zero 1st byte
  208.         DEC     DI                        ;Point back to beginning of NEW rec
  209.         MOV     CX,DX                     ;Restore OLD file recs remaining count
  210.         LOOP    Compare_Next              ;Go check next record on OLD file
  211.         RET                               ;All done with COMPARE_FILE
  212.  
  213. ;-------------------------------------------;
  214. ;Search NEW file records for a matching key ;
  215. ;-------------------------------------------;
  216. Find_Matching_NEW_Rec:                    ;Search NEW file to match OLD file rec
  217.         POP     SI                        ;Restore pointer to current record
  218.         POP     DI                        ;Restore pointer to current record
  219.         SUB     SP,2                      ;Leave current NEW rec pointer on stak
  220.  
  221. Continue_NEW_file_Search:
  222.         ADD     DI,DSP_Rec_Len            ;Next record on NEW file
  223. ;  Are we at end of file on NEW file ?
  224.         CMP     DI,BP                     ;Compare current NEW rec with EOF
  225.         JB      Compare_Keys_NEW_Rec      ;IF not EOF, go compare this key
  226. ;  We are at END Of File (EOF) on NEW file on this search, so report deleted rec
  227.         CALL    Display_Deleted_MSG       ;Report that rec from OLD file deleted
  228.         POP     DI                        ;Point to last CURRENT rec on NEW file
  229.         MOV     CX,DX                     ;Restore OLD file recs remaining count
  230.         LOOP    Check_Next_OLD_rec        ;Go check next record on OLD file
  231.         RET                               ;All done with COMPARE_FILE
  232. Compare_Keys_NEW_Rec:                     ; (1st 12 characters of each record)
  233.         MOV     CX,DSP_Key_Len/2          ;Compare 12 character key (6 words)
  234.         PUSH    DI                        ;Save current NEW rec loc
  235.         PUSH    SI                        ;Save current OLD rec loc
  236.         REPE    CMPSW                     ;Do compare
  237.         JE      Match_rest_of_NEW_Rec     ;If keys =, check the records
  238.         POP     SI                        ;Point back to start of this OLD rec
  239.         POP     DI                        ;Point back to start of this NEW rec
  240.         JMP     SHORT Continue_NEW_File_Search  ;Keek searching through NEW rec
  241.  
  242. Match_rest_of_NEW_Rec:                    ;NEW file scan has found matching keys
  243. ;       Now compare the actual records (keys already match):
  244. ;       ***Warning*** the length field of following instr may be patched by /O
  245. PATCH2: MOV     CX,18                     ;Check remainder of record (18 words)
  246.         INC     DI                        ;Skip checking next blank separator
  247.         INC     SI                        ;Skip checking next blank separator
  248.         REPE    CMPSW                     ;Do compare
  249.         POP     SI                        ;Point back to start of this OLD rec
  250.         POP     DI                        ;Point back to start of this NEW rec
  251.         JE      Found_matching_NEW_rec    ;If the records match
  252.         CALL    Display_changed_MSG       ;Report detection of changed record
  253. Found_matching_NEW_rec:
  254. ;       Now zero out 1st byte of the matched NEW file record:
  255.         XOR     AX,AX                     ;Zeros to store on key of record
  256.         STOSB                             ;Store zero byte at start of record
  257.         POP     DI                        ;point to last current rec on NEW file
  258.         MOV     CX,DX                     ;Restore OLD file recs remaining count
  259.         LOOP    Check_Next_OLD_rec        ;Go check next record on OLD file
  260.         RET                               ;All done with COMPARE_FILE
  261.  
  262.  
  263.  
  264. ;---------------------------------------------------------------------------;
  265. ; Scan for Additions:                                                       ;
  266. ;   Scan through the NEW file and look for records which have not had the   ;
  267. ;   1st byte zeroed. These recs represent added files. We will put out a     ;
  268. ;   message recording this fact.                                            ;
  269. ; ENTRY:  ES is segment register for NEW file                                ;
  270. ;---------------------------------------------------------------------------;
  271. Scan_for_Additions:
  272.         MOV     AX,CS                     ;Used to access normal DATA segment
  273.         MOV     DS,AX                     ;DS=CS  (normal DATA segment)
  274.         CMP     Changes_only,'Y'          ;Does user want only changes?
  275.         JNE     Scan_continue             ;   If not execute rest of procedure
  276. Scan_early_Exit:
  277.         RET                               ;   Otherwise, pack up and go home
  278. Scan_continue:
  279.         MOV     CX,NEW_Rec_Count          ;Get # of 51 char recs on NEW file
  280.         JCXZ    Scan_Early_Exit           ;If no NEW records to scan
  281.         MOV     DI,NEW_File_Start         ;1st record on NEW file
  282.         SUB     DI,DSP_Rec_Len            ;Point to record # -1
  283.         MOV     AX,ES                     ;Use both segment regs for NEW file
  284.         MOV     DS,AX
  285. Check_for_Next_Addition:
  286.         ADD     DI,DSP_Rec_Len            ;Look at next NEW file record
  287.         CMP     BYTE PTR [DI],0           ;Is this a zeroed record?
  288.         JE      Continue_Zero_Check       ;  If zeroed, keep checking
  289.         CALL    Display_Added_MSG         ;  Else record file addition
  290. Continue_Zero_Check:
  291.         LOOP    Check_For_Next_Addition
  292.         RET
  293.  
  294. ;---------------------------------------------------------------------------;
  295. ; COMPARE TOTALS  - If both OLD and NEW files have total lines check that   ;
  296. ;   they match. If they match, yet files were changed then put out a message;
  297. ;   to that effect and return ERRORLEVEL 4 at termination (BL reg).         ;
  298. ; ENTRY:  ES is segment register for NEW file                               ;
  299. ; EXIT:   DS is back to original Data Segment (=CS)                         ;
  300. ;         BL = 4 if records have changed but both totals match.             ;
  301. ;---------------------------------------------------------------------------;
  302. Compare_totals:                           ;Check if total===> lines match
  303.         MOV     AX,CS                     ;Set DS back to datasegment
  304.         MOV     DS,AX
  305.         MOV     SI,OLD_Tot_Loc            ;Point to location of totals
  306.         OR      SI,SI                     ;Check if totals line non-exist (SI=0)
  307.         JNE     Continue_totals_1         ;  If it exists, chk other totals line
  308.         RET                               ;  ELSE pack up and go home
  309. Continue_totals_1:
  310.         MOV     DI,NEW_Tot_Loc            ;Point to location of totals
  311.         OR      DI,DI                     ;Check if totals line non-exist (DI=0)
  312.         JNE     Continue_totals_2         ;  If it exists, compare the totals
  313.         RET                               ;  ELSE pack up and go home
  314. Continue_totals_2:
  315.         CMP     BH,0FFh                   ;See if page mode is off (= FFh)
  316.         JE      Continue_totals_3         ;   IF turned off, skip page control
  317.         MOV     AL,1                      ;   Else Set lines to be output to 2
  318.         CALL    Page_Control              ;     +  check if its time to pause
  319. Continue_totals_3:
  320.         MOV     AX,ES                     ;NEW file segment
  321.         SUB     AX,File_Size_PARAs        ;Backup 64K
  322.         MOV     DS,AX                     ;DS is OLD file segment register again
  323.         MOV     CX,9                      ;Compare 9 characters
  324.         REPE    CMPSB                     ;Compare
  325.         MOV     AX,CS                     ;Set DS back to datasegment
  326.         MOV     DS,AX
  327.         MOV     BP,BX                     ;Save highest errorlevel + line ct
  328.         MOV     BX,1                      ;Handle for std output device
  329.         JE      Totals_Match
  330.         MOV     DX, offset Tot_nomatch_MSG
  331.         MOV     CX,21                     ;Length of msg is 21 chars
  332.         MOV     AH,40h                    ;DOS Write func
  333.         INT     21h                       ;Tell user that totals don't match
  334.         MOV     BX,BP                     ;Restore saved BX (ERRLVL + LINEct)
  335.         RET
  336. Totals_match:
  337.         MOV     DX, offset Tot_match_MSG
  338.         MOV     CX,19                     ;Length of msg
  339.         MOV     AH,40h                    ;DOS Write func
  340.         INT     21h                       ;Tell user file totals are equal
  341.         MOV     BX,BP                     ;Restore saved BX (ERRLVL + LINEct)
  342.         OR      BL,BL                     ;Check if any file chgs,dels or adds
  343.                                           ;           (IE, BL not = 0)
  344.         JE      Totals_Return             ;   If no changes then we are done...
  345.         MOV     BL,4                      ;   ELSE, indicate probable rename
  346. Totals_Return:
  347.         RET
  348.  
  349. ;----------------------------------------------------------------------------;
  350. ; Display CHANGED Message:                                                   ;
  351. ;                                                                            ;
  352. ;ENTRY: DS:SI points to OLD version of report record to format + display.    ;
  353. ;       ES:DI points to NEW version of report record to format + display.    ;
  354. ;EXIT:                                                                       ;
  355. ;   Displays a message to standard output device informing user that a change;
  356. ;   has occured between the OLD and NEW files. IF /P was selected then       ;
  357. ;   we check line count and pause every 24 lines.                            ;
  358. ;----------------------------------------------------------------------------;
  359. Display_changed_MSG:                  ;Display message announcing changed record
  360.         PUSH    BP
  361.         PUSH    CX
  362.         PUSH    DX
  363.         PUSH    DS                        ;Save (OLD) file segment
  364.         MOV     AX,CS                     ;Used to access normal DATA segment
  365.         MOV     DS,AX                     ;DS=CS  (normal DATA segment)
  366.         OR      BL,BL                     ;Check if highest error level (BL) = 0
  367.         JNZ     Check_CHG_Page_mode       ;  If not 0, then header msg alrdy out
  368.         CALL    Display_Header_MSG        ;  Else Display the header message
  369. Check_CHG_Page_mode:
  370.         CMP     BH,0FFh                   ;See if page mode is off (= FFh)
  371.         JE      Display_changed_cont      ;   IF turned off, skip page control
  372.         MOV     AL,2                      ;   Else Set lines to be output to 2
  373.         CALL    Page_Control              ;     +  check if its time to pause
  374. Display_changed_cont:
  375.         MOV     BP,BX                     ;Save BX in BP
  376.         MOV     DX, offset CHGD_MSG_1     ;First part of changed messaged
  377.         MOV     CX,10                     ;Length of msg is 10 chars
  378.         MOV     AH,40h                    ;DOS Write func
  379.         MOV     BX,1                      ;BX=1 = Handle for std output device
  380.         INT     21h                       ;Write beginning of OLD file chngd msg
  381.         POP     DS                        ;Use file segment again (OLD file)
  382.         SUB     SP,2                      ;Leave DS on stack
  383.         MOV     DX,SI                     ;Point to OLD record
  384.         MOV     CX,DSP_Rec_Len            ;Length of display record
  385.         MOV     AH,40h                    ;DOS Write func
  386.         INT     21h                       ;Write actual OLD record out
  387.         MOV     AX,CS                     ;Used to access normal DATA segment
  388.         MOV     DS,AX                     ;Back to normal data segment again
  389.         MOV     DX, offset CHGD_MSG_2     ;First part of changed messaged
  390.         MOV     CX,10                     ;Length of msg is 10 chars
  391.         MOV     AH,40h
  392.         INT     21h                       ;Write beginning of OLD file chngd msg
  393.         MOV     AX,ES                     ;Use file segment again (NEW file)
  394.         MOV     DS,AX
  395.         MOV     DX,DI                     ;Point to NEW record
  396.         MOV     CX,DSP_Rec_Len            ;Length of display record
  397.         MOV     AH,40h
  398.         INT     21h                       ;Write actual OLD record out
  399.         MOV     BX,BP                     ;Restore Saved version of BX
  400.         POP     DS                        ;Restore addressability to OLD file
  401.         POP     DX
  402.         POP     CX
  403.         POP     BP
  404.         MOV     BL,12                     ;Indicate a record has changed
  405.         RET
  406.  
  407. ;---------------------------------------------------------------------------;
  408. ; Display DELETED Message                                                   ;
  409. ;                                                                           ;
  410. ; Entry: DS:SI must point to 51 chr DSP_REC (display record) to be displayed;
  411. ;                                                                           ;
  412. ;   Displays a message to standard output device informing user that a file ;
  413. ;   has been deleted from the OLD file list.   IF /P was selected then      ;
  414. ;   we check line count and pause every 24 lines.                           ;
  415. ;---------------------------------------------------------------------------;
  416. Display_Deleted_MSG:                 ;Display message announcing deleted records
  417.         PUSH    BP
  418.         PUSH    CX                        ;Save used registers
  419.         PUSH    DX
  420.         PUSH    DS                        ;Save (OLD) file segment
  421.         MOV     AX,CS                     ;Used to access normal DATA segment
  422.         MOV     DS,AX                     ;DS=CS  (normal DATA segment)
  423.         CMP     Changes_only,'Y'          ;Does user want only changes?
  424.         JNE     Display_Deleted_continue  ;   If not continue
  425.         POP     DS                        ;   ELSE restore DS and return
  426.         JMP     Display_Deleted_Exit2     ;                           to caller
  427. Display_Deleted_continue:
  428.         OR      BL,BL                     ;Check if highest error level (BL) = 0
  429.         JNZ     Check_DEL_Page_mode       ;  If not 0, then header msg alrdy out
  430.         CALL    Display_Header_MSG        ;  Else Display the header message
  431. Check_DEL_Page_mode:
  432.         CMP     BH,0FFh                   ;See if page mode is off (= FFh)
  433.         JE      Display_deleted_continue2 ;   IF turned off, skip page control
  434.         MOV     AL,1                      ;   Else Set lines to be output to 2
  435.         CALL    Page_Control              ;     +  check if its time to pause
  436. Display_deleted_continue2:
  437.         MOV     BP,BX                     ;Save BX
  438.         MOV     DX, offset DELETED_MSG    ;First part of deleted message
  439.         MOV     CX,10                     ;Length of msg is 10 chars
  440.         MOV     AH,40h                    ;DOS Write func
  441.         MOV     BX,1                      ;Handle for std output device
  442.         INT     21h                       ;Write beginning of OLD file deltd msg
  443.         POP     DS                        ;Use file segment again (OLD file)
  444.         MOV     DX,SI                     ;Point to OLD record
  445.         MOV     CX,DSP_Rec_Len            ;Length of each display record
  446.         MOV     AH,40h                    ;DOS Write func
  447.         INT     21h                       ;Write actual OLD record out
  448. Display_Deleted_Exit:
  449.         MOV     BX,BP                     ;Restore saved version of BX
  450.         CMP     BL,8                      ;Check if Delete or chg already hapnd
  451.         JAE     Display_Deleted_Exit2     ;   Do not change if already set
  452.         MOV     BL,8                      ;Flag that Deleted record detected
  453. Display_Deleted_Exit2:
  454.         POP     DX
  455.         POP     CX
  456.         POP     BP
  457.         RET
  458.  
  459.  
  460. ;---------------------------------------------------------------------------;
  461. ;Display ADDED Message  -Indicate that a file has been added since OLD reprt;
  462. ;                                                                           ;
  463. ;ENTRY: ES:DI points to NEW version of report record to format + display.   ;
  464. ;EXIT:                                                                      ;
  465. ;   Prints a message to standard output device informing user that a file   ;
  466. ;   has been added to the NEW file list.   IF /P was selected then          ;
  467. ;   we check line count and pause every 24 lines.                           ;
  468. ;---------------------------------------------------------------------------;
  469. Display_Added_MSG:                  ;Display message announcing additional files
  470.         PUSH    BP
  471.         PUSH    CX                        ;Save used registers
  472.         MOV     AX,CS                     ;Used to access normal DATA segment
  473.         MOV     DS,AX                     ;DS=CS  (normal DATA segment)
  474.         OR      BL,BL                     ;Check if highest error level (BL) = 0
  475.         JNZ     Check_ADD_Page_mode       ;  If not 0, then header msg alrdy out
  476.         CALL    Display_Header_MSG        ;  Else Display the header message
  477. Check_ADD_Page_mode:
  478.         CMP     BH,0FFh                   ;See if page mode is off (= FFh)
  479.         JE      Display_Added_continue    ;   IF turned off, skip page control
  480.         MOV     AL,1                      ;   Else Set lines to be output to 2
  481.         CALL    Page_Control              ;     +  check if its time to pause
  482. Display_Added_continue:
  483.         MOV     BP,BX                     ;Save BX
  484.         MOV     DX, offset Added_MSG      ;First part of deleted message
  485.         MOV     CX,10                     ;Length of msg is 10 chars
  486.         MOV     AH,40h                    ;DOS Write func
  487.         MOV     BX,1                      ;Handle for std output device
  488.         INT     21h                       ;Write beginning of OLD file added msg
  489.         MOV     AX,ES                     ;Use file segment again (NEW file)
  490.         MOV     DS,AX                     ;DS=ES (both are seg reg for NEW file)
  491.         MOV     DX,DI                     ;Point to rec on NEW file (Added rec)
  492.         MOV     CX,DSP_Rec_Len            ;Length of display record
  493.         MOV     AH,40h                    ;DOS Write func
  494.         INT     21h                       ;Write actual OLD record out
  495.         MOV     BX,BP                     ;Restore saved version of BX
  496.         POP     CX
  497.         POP     BP
  498.         CMP     BL,8                      ;Chk if Del, add or chg already hapnd
  499.         JAE     AD_or_CHG_happened        ;   Do not change if already set
  500.         MOV     BL,8                      ;Flag that Deleted record detected
  501. AD_or_CHG_happened:
  502.         RET
  503.  
  504. ;---------------------------------------------------------------------------;
  505. ; Allocate Memory                                                           ;
  506. ;                                                                           ;
  507. ; ENTRY: BX contains starting offset of buffer area.                        ;
  508. ;        (Note, this area contains initialization code and data which will  ;
  509. ;        be overlaid once we start reading into the buffers.)               ;
  510. ;                                                                           ;
  511. ;   Release memory used by initialization routine and allocate 2000h pages  ;
  512. ;   (128k) memory for use as file buffers. If this fails get as much as     ;
  513. ;   possible. Divide memory allocated into 2 buffers - 1 for each file.     ;
  514. ;   Leaves ES as segment pointer to first file segment (OLD file)           ;
  515. ;---------------------------------------------------------------------------;
  516. Allocate_Memory:
  517.  
  518. ; Now determine how many paragraphs (16 bytes) program plus stack needs:
  519.         ADD     BX,15                     ;Round up to nearest PARA
  520.         MOV     CL,4
  521.         SHR     BX,CL                     ;Divide bytes of storage by 16
  522.  
  523.         MOV     AH,4Ah                    ;Dealloc all but needed (BX) paras
  524.         INT     21h
  525.  
  526.         MOV     BX,2000h                  ;Request 128K for input buffers
  527.         MOV     AH,48h                    ;DOS request mem function
  528.         INT     21h
  529.         JNC     Mem_OK                    ;If memory is available
  530.  
  531.         MOV     DX,offset Mem_loss_Msg    ;Display msg informing lack of mem
  532.         MOV     AH,09H                    ;DOS display string function
  533.         INT     21H
  534. ; Attempt to allocate what little memory is available and use that
  535.         MOV     AX,BX                     ;Paragraphs of memory free
  536.         SHR     AX,1                      ;Divide by two: Space for each file
  537.         MOV     File_Size_PARAs,AX        ;Each file's size in pargraphs
  538.         MOV     CL,4                      ;Prepare to shift left 4 bits (*16)
  539.         SHL     AX,CL                     ;Mult by 16 = number of bytes per file
  540.         MOV     File_Size_Bytes,AX        ;Space for each file in bytes
  541.         MOV     AH,48h                    ;DOS alloc mem func:BX = para avail
  542.         INT     21h                       ;Get what memory we can get
  543.         JNC     Mem_OK                    ;If Alloc worked 2nd time around
  544.  
  545. ; Fatal memory error:
  546.         MOV     DX,offset Mem_ERR_Msg     ;Else: give message and give up
  547.         MOV     AH,09H                    ;DOS display string function
  548.         INT     21H
  549.         CALL    Page_Wait                 ;Beep and force user to hit a key
  550.         MOV     AX,4C14h                  ;   terminate with 20 error level
  551.         INT     21h
  552.  
  553. Mem_OK:
  554.         MOV     ES,AX                     ;ES points to start of allcoated block
  555.         RET
  556.  
  557. ;---------------------------------------------------------------------------;
  558. ; Read and Validate Files                                                   ;
  559. ;   1) Read both files into file buffers.                                   ;
  560. ;   2) Validate that files are of correct type                              ;
  561. ;   3) Determine offset of first record and total number of records         ;
  562. ;      check if a total line exists on each file                            ;
  563. ;   4) Calc offset of beginning of last record for the NEW file             ;
  564. ;                                                                           ;
  565. ; On Entry ES must point to OLD_FILE segment                                ;
  566. ;                                                                           ;
  567. ; On Exit  ES will point to NEW_FILE segment  and DS will DATA SEG (=CS)    ;
  568. ;---------------------------------------------------------------------------;
  569. Read_and_Validate_Files:
  570.  
  571. ;  Read "OLD" file (first of two files specified)
  572.         MOV     BX,OLD_File_Handle        ;Get handle for the first file
  573.         PUSH    OLD_Filename_end          ;Save end of Filename on stack
  574.         PUSH    OLD_Filename_Loc          ;Save start of filename for error msgs
  575.         MOV     AX,ES                     ;ES points to beginning of file SEG
  576.         MOV     DS,AX                     ;DS=ES = seg reg for OLD file
  577.         CALL    Read_File                 ;Do actual read of file + error chking
  578.         CALL    Validate_File             ;Check file and locate 1st + last recs
  579.                                           ;DS=CS after return from Validate_File
  580.         ADD     SP,4                      ;Remove filename end + loc from stack
  581.         MOV     OLD_File_Start,BP         ;Save 1st record address
  582.         MOV     OLD_Rec_count,CX          ;Save number of records
  583.         MOV     OLD_Tot_Loc,BX            ;Save location of totals (if existing)
  584.  
  585. ;  Read "NEW" file (2nd of two files specified)
  586.         MOV     BX,NEW_File_Handle        ;Get handle for the first file
  587.         PUSH    NEW_Filename_end          ;Save end of Filename on stack
  588.         PUSH    NEW_Filename_Loc          ;Save start of filename for error msgs
  589.         MOV     AX,ES                     ;DS points to beginning of file SEG
  590.         ADD     AX,File_Size_PARAs        ;point DS to NEW file segment
  591.         MOV     DS,AX                     ;DS is segment register for NEW file
  592.         CALL    Read_File                 ;Do actual read of file + error chking
  593.         MOV     AX,DS                     ;Validate_file needs
  594.         MOV     ES,AX                     ;                    ES for file seg
  595.         CALL    Validate_File             ;Check file and locate 1st + last recs
  596.                                           ;DS = CS after return from Validate_Fi
  597.         ADD     SP,4                      ;Remove filename end + loc from stack
  598.         MOV     NEW_File_Start,BP         ;Save 1st record address
  599.         MOV     NEW_Rec_count,CX          ;Save number of records
  600.         MOV     NEW_Tot_Loc,BX            ;Save location of totals (if existing)
  601.         MOV     New_End_Of_File,DI        ;Save start of last rec on NEW file
  602.         RET
  603.  
  604. ;---------------------------------------------------------------------------;
  605. ; READ FILE - will read the file specified by the following parameters      ;
  606. ;   BX contains file handle, Stack contains end and start of  filespec      ;
  607. ;   DS contains segment to read file into (file buffer is at offset zero)   ;
  608. ; On EXIT:  File will be read into file buffer pointed to by DS and closed. ;
  609. ;           CX will contain number of characters read in from  the file.    ;
  610. ;---------------------------------------------------------------------------;
  611. Read_file:
  612.         CMP     CS:Missing_Old_File,'Y'   ;Are we attempting to read from a
  613.                                           ; Non existant OLD file?
  614.         JNE     Normal_File_Read          ;   If not, do normal file read
  615.         XOR     CX,CX                     ;   Else, indicate file is empty
  616.         MOV     CS:Missing_Old_File,0     ;   Turn off missing file switch
  617.         RET                               ;   All done for missing file
  618.  
  619. Normal_File_Read:
  620.         XOR     DX,DX                     ;DX=0 = start of  file buffer
  621.         MOV     SI,DX                     ;SI is for BUFFER reads later
  622.         MOV     CX,CS:File_Size_Bytes     ;MAX # of bytes to read (64k-1)
  623.         MOV     AH,3FH                    ;Setup to read from file
  624.         INT     21H                       ;Call DOS to do actual read
  625.         JC      Read_error                ;Quit on any error or EOF
  626.         OR      AX,AX                     ;Check if ax=0 no records read
  627.         JZ      File_size_error           ;If no records, close this file..
  628.         CMP     AX,CX                     ;See if max number of chars read
  629.         JE      File_size_error           ;If we have compltly filled buffer
  630.         MOV     CX,AX                     ;Save total # of chars read
  631.         MOV     AH,3Eh                    ;Prepare to close the file
  632.         INT     21H                       ;Let DOS close file
  633.         RET
  634.  
  635. ;---------------------------------------------------------------------------;
  636. ; READ ERROR - report read error message - call with:                       ;
  637. ;   Stack contains the END and (LOC) start of the filespec for error msgs   ;
  638. ;---------------------------------------------------------------------------;
  639. Read_error:                               ;Report error reading a file
  640.         MOV     AX,CS
  641.         MOV     DS,AX                     ;Restore datasegment addresability
  642.         MOV     DX, offset Read_Err_MSG   ;indicate read failed
  643.         MOV     CX,15                     ;Length of msg is 15 chars
  644.         MOV     SI,4C14h                  ;DOS term with error level 20
  645.         JMP     Report_file_errors
  646.         SUBTTL  General Purpose subroutines
  647.  
  648. ;---------------------------------------------------------------------------;
  649. ; FILE SIZE ERROR - Report on an error - with file have too many records    ;
  650. ;   Stack contains the END and (LOC) start of the filespec for error msgs   ;
  651. ;---------------------------------------------------------------------------;
  652. File_size_error:                          ;File has  more than 64k records
  653.         MOV     AX,CS
  654.         MOV     DS,AX                     ;Restore datasegment addresability
  655.         MOV     DX, offset size_Err_MSG   ;indicate record has an invalid size
  656.         MOV     CX,20                     ;Length of msg is 20 chars
  657.         MOV     SI,4C10h                  ;DOS term with error level 16 (dec)
  658.         JMP     Report_file_errors
  659.  
  660. ;---------------------------------------------------------------------------;
  661. ; FILE TYPE ERROR - Report on an error - with file being invalid type       ;
  662. ;   Stack contains the END and (LOC) start of the filespec for error msgs   ;
  663. ;---------------------------------------------------------------------------;
  664. File_type_error:                          ;Report this is wrong type of file
  665.         ADD     SP,2                      ;Remove CX from the stack; this way:
  666.                                           ;   filespec_end + loc are stack top
  667.         MOV     AX,CS
  668.         MOV     DS,AX                     ;Restore datasegment addresability
  669.         MOV     DX, offset type_Err_MSG   ;indicate invalid record type
  670.         MOV     CX,20                     ;Length of msg is 20 chars
  671.         MOV     SI,4C10h                  ;DOS term with error level 16 (dec)
  672.         JMP     Report_file_errors
  673.  
  674. ;---------------------------------------------------------------------------;
  675. ; VALIDATE FILE - will examine file and locate 1st and last records in file ;
  676. ; On Entry:                                                                 ;
  677. ;   Stack contains the END and (LOC) start of the filespec for error msgs   ;
  678. ;   ES contains File buffer SEGMENT                                         ;
  679. ;   CX contains number of characters read in the buffer                     ;
  680. ; On EXIT: (if file is of valid type:)                                      ;
  681. ;   BP will be beginning of 1st record on file (offset)                     ;
  682. ;   CX will be count of number of records on file                           ;
  683. ;   BX will be = offset of CHKSUM field on final total=====> record         ;
  684. ;   DI will be offset of last char in last 51 char record on the file (EOF) ;
  685. ;   DS will be code/data segment register rather than File segment          ;
  686. ;---------------------------------------------------------------------------;
  687. Validate_File:
  688.         MOV     AX,CS                     ;XFER OLD data SEG(=CS)
  689.         MOV     DS,AX                     ;                        back into DS
  690.  
  691.         CMP     CX,0                      ;Is this a pretend file (empty) ?
  692.         JNE     Its_a_Real_File           ;If not, do actual validation
  693.         XOR     DI,DI                     ;Set EOF offset to empty
  694.         XOR     BX,BX                     ;Indicate for totals record
  695.         RET                               ;All done
  696.  
  697. Its_a_Real_File:
  698.         PUSH    CX                        ;Save copy of offset of EOF
  699.         XOR     DI,DI                     ;Start at beginning of buffer
  700.         MOV     AL,254                    ;Search for teltale of CHKfile (box)
  701.         REPNE   SCASB                     ;Search until match
  702.         JNZ     File_type_error           ;If no match found
  703.         MOV     AL,'W'                    ;Search for teltale of CHKfile
  704.         REPNE   SCASB                     ;Search until match
  705.         MOV     BX,CX                     ;Save copy of CX
  706.         MOV     CX,4                      ;Compare 8 characters
  707.         MOV     SI,offset Check_String
  708.         REPE    CMPSW                     ;File should match exactly
  709.         JNZ     File_type_error           ;If mismatch found
  710.         MOV     CX,BX                     ;Restore CX to
  711.         SUB     CX,8                      ;              reflect chars left
  712.         MOV     AL,'-'                    ;Search for a
  713.         REPNE   SCASB                     ;             minus sign
  714.         MOV     AL,LF                     ;Search for a
  715.         REPNE   SCASB                     ;             linefeed character
  716.         JNZ     File_type_error           ;If no match found
  717.         MOV     BP,DI                     ;Save this location (1st record)
  718. ; BP now points to the first 51 char display record on this file
  719.  
  720. ; Now check for existance of TOTALS==> record and locate beginning of last rec
  721.         XOR     DX,DX                     ;Zero upper part of dividend (DX:AX)
  722.         MOV     AX,CX                     ;# of chars after start of 1st record
  723.         MOV     BX,DSP_Rec_Len            ;Prepare to divide by record len (51)
  724.         DIV     BX                        ;Divide chars from 1st rec by rec len
  725. ;       After divide: # of 51 char recs is in AX; # of chars in last rec in DX
  726.         MOV     CX,AX                     ;# of 51 character records on file
  727.         XOR     BX,BX                     ;  Initially indicate no totals line
  728.         OR      DX,DX                     ;Check if, no total line (no last rec)
  729.         JZ      No_totals_line            ;Skip totals line checking
  730.         CMP     DX,24                     ;Totals line should be 24 characters
  731.         JE      Tot_line_exists           ;   If length is correct for tot line
  732.         JMP     File_type_error           ;   If length of final line is wrong
  733. Tot_line_exists:
  734.         POP     DI                        ;Get address of EOF (PUSHed CX)
  735.         SUB     DI,10                     ;first char in CHKSUM field of TOT rec
  736.         MOV     BX,DI                     ;  Return this location to caller
  737.         SUB     DI,13                     ;Point DI past end of last 51 chr rec
  738.         RET
  739. No_totals_line:
  740.         POP     DI                        ;Get address of EOF (PUSHed CX)
  741.                                           ;DI= offset past last 51 char record
  742.         RET                               ;End of VALIDATE_FILE routine
  743.  
  744.         PAGE
  745. ;******************************************************************************;
  746. ;**   General purpose subroutines follow                                     **;
  747. ;******************************************************************************;
  748.  
  749. ;---------------------------------------------------------------------------;
  750. ; Report File errors  - General purpose error presenter used by             ;
  751. ;    the specific error subroutines such as file_size_error + read_error.   ;
  752. ;   Stack contains the END and (LOC) start of the filespec which had error. ;
  753. ;   DX = offset to error msg, CX has length of message                      ;
  754. ;   SI = contains DOS terminate code with specific ERRORLEVEL in lower part ;
  755. ;---------------------------------------------------------------------------;
  756. Report_File_errors:                       ;General purpose error display routine
  757.                                           ;DOS term func + errlvl must be in SI
  758.         MOV     AX,CS                     ;Point ES back
  759.         MOV     ES,AX                     ;              to normal data segment
  760.         MOV     AH,40h                    ;DOS Write func
  761.         MOV     BX,1                      ;Handle for std output device
  762.         INT     21h                       ;Write beginning of error message
  763.         ADD     SP,2                      ;Remove return address from stack
  764.         POP     BP                        ;Get starting offset of filespec
  765.         POP     DI                        ;1 character after end of filespec
  766.         MOV     AX,CRLF                   ;Terminate file name with CR,LF
  767.         STOSW
  768.         SUB     DI,BP                     ;Calc filename length + 2 for CRLF
  769.         MOV     CX,DI
  770.         MOV     DX,BP                     ;Start of file name to output
  771.         MOV     AH,40h                    ;DOS Write func
  772.         INT     21H
  773.         CALL    Page_Wait                 ;Beep and force user to hit a key
  774.         MOV     AX,SI                     ;SI contains 4Ch with error lvl
  775.         INT     21h
  776.  
  777.  
  778. ;---------------------------------------------------------------------------;
  779. ; Page_control:       (and *PAGE WAIT*   alternate entry point)             ;
  780. ;  Called only if user specified /P option (BH will be not = to FFh).       ;
  781. ;  Page control will increment the line counter and pause every 24 lines    ;
  782. ;  giving the user a prompt to -Hit any KEY -                               ;
  783. ;ENTRY:                                                                     ;
  784. ;   AL contains number of lines waiting to be displayed.                    ;
  785. ;   BH contains line count for this page already.                           ;
  786. ;   DS points to normal data segment (=CS)                                  ;
  787. ;EXIT:                                                                      ;
  788. ;   BH contains updated line count which is reset if page wait happened     ;
  789. ;                                                                           ;
  790. ;PAGE WAIT - simply puts out -HIT ANY KEY- message and waits for user       ;
  791. ;            to hit any key.                                                ;
  792. ;---------------------------------------------------------------------------;
  793. Page_control:
  794.         ADD     BH,AL                     ;Increment line counter
  795.         CMP     BH,24                     ;Are we over one page of output?
  796.         JA      Page_Wait                 ;   If over 1 page then do page wait
  797.         RET
  798. Page_Wait:                                ;Alternate entry point (here)
  799.         MOV     BH,AL                     ;Reset the line counter
  800.  
  801.         PUSH    BP                        ;Save all corrupted registers
  802.         PUSH    BX
  803.         PUSH    CX
  804.         PUSH    DI
  805.         PUSH    DX
  806.         PUSH    SI
  807. ; Produce a beep to alert the user:  (use  BIOS TTY func to write an ASCII BELL)
  808.         MOV     AX,0E07H                  ;BIOS func (0Eh) to write (07H) beep
  809.         XOR     BH,BH                     ;Select page zero for output
  810.         INT     10H                       ;BIOS video function (0Eh=write char)
  811.  
  812. ;Find out what attribute is being used for display
  813.         MOV     AH,08h                    ;read attrib + char function
  814.         INT     10h                       ;Call BIOS
  815.         PUSH    AX                        ;Save AH=attribute byte
  816.  
  817. ;Find out what line the cursor is on
  818.         MOV     AH,03h                    ;Read cursor position function
  819.         INT     10h                       ;BIOS video services
  820.         PUSH    DX                        ;DH contains row (line #) Save it!
  821.  
  822. ; Position cursor to current line + column 28: (TO BIOS  row 27)
  823.         MOV     AH,02                     ;BIOS int 10h set cursor position func
  824.         XOR     BH,BH                     ;Set page to zero
  825.                                           ;DH contains current row
  826.         MOV     DL,1Bh                    ;Set cusor current row and col 27
  827.         INT     10h                       ;BIOS video services
  828.  
  829. ; Put -Hit any key- message out with inverse video attribute type on
  830. ;       XOR     BH,BH                     ;Set page to zero  (BH is still 0)
  831.         MOV     BL,0F0h                   ;Inverse video attribute
  832.         MOV     CX,1                      ;Character count
  833.         MOV     SI,offset Hit_Key_Msg     ;The hit-any-key message
  834. Display_next_video_char:
  835.         MOV     AH,09H                    ;BIOS int 10h write attrib + char func
  836.         LODSB                             ;Get next character for output
  837.         PUSH    SI                        ;Save SI (int 10h may corrupt it)
  838.         INT     10h                       ;Put character and attribute out
  839.         INC     DX                        ;Advance cursor position
  840.         MOV     AH,02                     ;Adv cursor function
  841.         INT     10h                       ;   advance the cursor (BIOS)
  842.         POP     SI                        ;Restore saved SI
  843.         CMP     SI,offset Hit_key_Msg_end ;are we at end of message?
  844.         JB      Display_next_video_char   ;  If not get next char for display
  845.                                           ;  Else, wait for key press by user
  846. ; Wait for user to hit any key
  847.         XOR     AX,AX
  848.         INT     16h                       ;Wait for user to hit a key
  849.  
  850. ; Erase HIT ANY KEY message
  851.         POP     DX                        ;DH=current line number
  852.         POP     BX                        ;BH=user's screen attribute
  853.         MOV     AH,06h                    ;INIT window function
  854.         XOR     AL,AL                     ;Zero AL to clear window
  855.         MOV     CH,DH                     ;Current row (y coor upr lft)
  856.         MOV     CL,00                     ;Start in first char position
  857.         MOV     DL,79                     ;Last char pos - blank entire line
  858.         INT     10h                       ;Blank out line
  859.  
  860. ; Position cursor to start of blanked line
  861.         MOV     AH,02                     ;BIOS int 10h set cursor position func
  862.         XOR     DL,DL                     ;DH=cur line, DL=0: first char pos
  863.         XOR     BX,BX                     ;Use video page zero
  864.         INT     10h                       ;BIOS video services
  865.  
  866.         POP     SI                        ;Restore all corrupted registers
  867.         POP     DX
  868.         POP     DI
  869.         POP     CX
  870.         POP     BX
  871.         POP     BP
  872.         RET                               ;Return to caller
  873.  
  874. ;---------------------------------------------------------------------------;
  875. ; Display HEADER MSG - displays column headers the first time CFCOMP decides;
  876. ;     it needs to display a changed record.                                 ;
  877. ;ENTRY:                                                                     ;
  878. ;   DS points to normal data segment (=CS)                                  ;
  879. ;EXIT:                                                                      ;
  880. ;   DX,CX,AX are corrupted.                                                 ;
  881. ;---------------------------------------------------------------------------;
  882. Display_Header_MSG:
  883.         PUSH    BX                        ;Save BX (error level in BL)
  884.         MOV     BX,1                      ;Write to STD output device (=1)
  885.         MOV     DX, offset Header_MSG     ;beginning loc of directory string
  886.         MOV     CX,179                    ;179 chars in header message
  887.         MOV     AH,40h                    ;DOS write
  888.         INT     21h
  889.         POP     BX
  890.         RET
  891.         SUBTTL  Definition of Data structures
  892.         PAGE
  893. ;******************************************************************************;
  894. ;**   Definition of Data areas follow                                        **;
  895. ;******************************************************************************;
  896. File_Size_PARAs  DW   1000h               ;Size of each REP file in paragraphs
  897. File_Size_Bytes  DW   0FFFFh              ;Size of each REP file in bytes
  898. OLD_Filename_Loc DW   0                   ;offset of filespec for OLD file
  899. OLD_Filename_end DW   0                   ;end of filespec for OLD file
  900. OLD_File_Handle  DW   0                   ;File handle  for OLD file
  901. OLD_File_Start   DW   0                   ;Offset of 1st record on file
  902. OLD_Rec_count    DW   0                   ;Number of 51 character recs on file
  903. OLD_Tot_Loc      DW   0                   ;Offset of CHKSUM on totals records
  904. NEW_Filename_Loc DW   0                   ;offset of filespec for NEW file
  905. NEW_Filename_end DW   0                   ;end of filespec for NEW file
  906. NEW_File_Handle  DW   0                   ;File handle for NEW file
  907. NEW_File_Start   DW   0                   ;Offset of 1st record on file
  908. NEW_Rec_count    DW   0                   ;Number of 51 character recs on file
  909. NEW_Tot_Loc      DW   0                   ;Offset of CHKSUM on totals records
  910. New_End_Of_File  DW   0                   ;Offset beginning of last record
  911. Changes_Only     DB   0                   ;="Y" if user wants only changes
  912. Missing_Old_File DB   0                   ;="Y" if OLD report file not found
  913. Page_Mode        DB   0FFh                ;=00h  means stop after each page
  914. Check_String     DB   'olfgang '
  915. Mem_Err_Msg      DB   'Error in MEM ALLOC'
  916. CRLF_Msg         DB   CR,LF,'$'
  917. Mem_loss_Msg     DB   'Memory lack limits file size'
  918.                  DB   CR,LF,'$'
  919. Read_Err_MSG     DB   'Error reading: '
  920. Type_Err_MSG     DB   'Wrong type of file: '
  921. Size_Err_MSG     DB   'File size invalid: '
  922. CHGD_MSG_1       DB   'Chgd: OLD:'
  923. CHGD_MSG_2       DB   '      NEW:'
  924. Deleted_MSG      DB   'Deleted-->'
  925. Added_MSG        DB   'NEW Fil-->'
  926. Tot_match_MSG    DB   'File totals match',CR,LF
  927. Tot_nomatch_MSG  DB   'File totals unequal',CR,LF
  928. Hit_Key_MSG      DB   '-Hit any key-'
  929. Hit_Key_MSG_end EQU $
  930. Header_MSG    DB  '          File Name + Check Check  File    Update   Update'
  931.               DB   CR,LF
  932.               DB  '          Extension:  Val1: Val2:  Size:   Date:    Time:'
  933.               DB   CR,LF
  934.               DB  '          ----------   ---- ----   -----   ------   ------'
  935.               DB   CR,LF
  936.  
  937.         SUBTTL  INIT data + code (also input BUFFERs + stack)
  938.         PAGE
  939. ;******************************************************************************;
  940. ;**   Definition of file buffer Data areas and code follow:                  **;
  941. ;** All the following storage will be overlaid when records are read in      **;
  942. ;******************************************************************************;
  943.  
  944.               EVEN
  945. Buffer_area   label  byte                 ;All storage + code following is in
  946.                                           ; the input file buffer.
  947.  
  948. ; ----------------------------------------------------------------------------;
  949. ; Initialization code - parse parms + put out msgs and open both files        ;
  950. ; ----------------------------------------------------------------------------;
  951. Parse_Parms_Open_Files:                   ;Parse input parameters + displ header
  952.         MOV     SI,80H                    ;Parameter area in PSP
  953.         MOV     CL,[SI]                   ;Get # of chars in input parm
  954.         XOR     CH,CH                     ;Clear upper byte of char count
  955.         INC     SI                        ;point to first char
  956.  
  957. ;---------------------------------------------------------------------------;
  958. ; Conventions for command line parsing:                                     ;
  959. ;   SI points to next char to be checked in the parm field at DS:80         ;
  960. ;   CX is count of characters left to be scanned                            ;
  961. ;   BP points to start of current processed filespec.                       ;
  962. ;---------------------------------------------------------------------------;
  963.  
  964.         Call    Parse_Filespec            ;exract 1st filespec from parm area
  965.         MOV     OLD_Filename_Loc,BP       ;Store location of file name
  966.         MOV     OLD_Filename_end,DI       ;Store char loc after end of filespec
  967. ;       Adjust CX to reflect actual characters left to be scanned
  968.         JCXZ    Skip_decrement            ;Don't decrement CX if already = 0
  969.         DEC     CX
  970. Skip_decrement:
  971.         Call    Parse_Filespec            ;exract 2nd filespec from parm area
  972.         MOV     NEW_Filename_Loc,BP       ;Store location of 2nd file name
  973.         MOV     NEW_Filename_end,DI       ;Store char loc after end of filespec
  974.  
  975.         CALL    Parse_parms               ;Process any "/" parms
  976.         CALL    Put_Out_Initial_MSGs      ;Display header and start messages
  977.  
  978.         MOV     DX,OLD_Filename_Loc       ;Open the first ("OLD") file
  979.         MOV     AX,3D00H                  ;DOS open file (handle) for read cmnd
  980.         INT     21H                       ;invoke DOS
  981.         JNC     Continue_Open             ;If no errors continue processing
  982.  
  983. ;       If open fails for OLD file, treat it as if file were empty - keep going
  984.         MOV     Missing_Old_File,'Y'      ;Else, Indicate old file was gone
  985.         MOV     DI,OLD_Filename_end
  986.         CALL    File_Open_Error           ;Put out file open error message
  987.         MOV     DX, OFFSET Empty_OLD_MSG  ;Tell user we will pretend file is MT
  988.         MOV     AH,09H                    ;DOS display string function
  989.         INT     21H
  990.  
  991. Continue_Open:
  992.         MOV     OLD_File_handle,AX        ;Save DOS file handle
  993.         MOV     DX,NEW_Filename_Loc       ;Open the 2nd (AKA "NEW") file
  994.         MOV     AX,3D00H                  ;DOS open file (handle) for read cmnd
  995.         INT     21H                       ;invoke DOS
  996.         JNC     Open_done                 ;If no errors continue processing
  997.         MOV     DI,NEW_Filename_end
  998.         CALL    File_Open_Error           ;Put out file open error message
  999.         CALL    Page_Wait                 ;Force user to acknoledge error
  1000.         MOV     AX,4C14h                  ;   terminate with 20 error level
  1001.         INT     21h
  1002.  
  1003. Open_done:
  1004.         MOV     NEW_File_handle,AX        ;Save DOS file handle
  1005.  
  1006.         RET
  1007.  
  1008. ;---------------------------------------------------------------------------;
  1009. ; Parse filespec:                                                           ;
  1010. ; Input:                                                                    ;
  1011. ;   SI points to next char to be checked in the parm field at DS:80         ;
  1012. ;   CX is count of characters left to be scanned                            ;
  1013. ;                                                                           ;
  1014. ; Returns:                                                                  ;
  1015. ;   BP points to start of filespec                                          ;
  1016. ;   DI points to byte after last char in filespec                           ;
  1017. ;   Filespec is zero terminated in the parameter area                       ;
  1018. ;---------------------------------------------------------------------------;
  1019. Parse_Filespec:                           ;Extract and zero terminate filename
  1020.         OR      CL,CL                     ;Check for 0 chars (NO INPUT)
  1021.         JZ      ERR_EXIT                  ;If no parms put out error msg
  1022. DEL_SPACES:
  1023.         LODSB                             ;Get byte at DS:SI and inc SI
  1024.         CMP     AL,' '                    ;Is it a space?
  1025.         JNE     Set_File_name             ;If not, we should have a file name..
  1026.         LOOP    DEL_SPACES                ;Cont checking until last char
  1027. ERR_EXIT:
  1028.         MOV     DX, OFFSET No_File_Msg    ;Prepare error message
  1029.         MOV     AH,09H                    ;DOS display string function
  1030.         INT     21H
  1031.         JMP     SHORT Give_Syntax_and_Quit ;Give correct syntax and terminate
  1032.  
  1033. ;--------------------------------------------;
  1034. ; Parse file spec and zero byte terminate it ;
  1035. ;--------------------------------------------;
  1036. Set_File_Name:
  1037.         DEC     SI                        ;point back to 1ST letter of filespec
  1038.         MOV     BP,SI                     ;Save a copy of filespec start
  1039.  
  1040. Scan_To_File_Spec_End:
  1041. ;       start scanning the file specification and transfer into output field
  1042.         LODSB                             ;Get next char of file spec
  1043.         CMP     AL,' '                    ;check valid separator character
  1044.         JBE     file_spec_end_found
  1045.         CMP     AL,'/'                    ;check for valid separator
  1046.         JE      file_spec_end_found
  1047.         CMP     AL,','                    ;check for valid separator
  1048.         JE      file_spec_end_found
  1049.         LOOP    Scan_To_File_Spec_End
  1050.         INC     SI                        ;Adjust SI if no separator char found
  1051.  
  1052. File_Spec_End_Found:
  1053. ;       SI is pointing 2 characters past end of filespec at this time
  1054.         MOV     DI,SI
  1055.         DEC     DI                        ;DI points to 1st char after filespec
  1056.         MOV     BYTE PTR [DI],00          ;zero terminate the filespec: ASCIIZ
  1057.         RET
  1058.  
  1059. ;----------------------------------------------------------------;
  1060. ;   Parse Parms:     parse /P and /C parameters                  ;
  1061. ;   Input:    SI must point to next character to process         ;
  1062. ;             CX contains # of chars left in paramter area       ;
  1063. ;----------------------------------------------------------------;
  1064. Parse_Parms:
  1065. Check_parm_chars_left:                    ;Check if enough chars left for a parm
  1066.         CMP     CX,01                     ;Check if we out of chars to scan
  1067.         JA      Parm_Scan                 ;   If Not, continue checking
  1068.         RET                               ;   If no more chars, we are done
  1069. Parm_Scan:                                ;Check for presence of a /_ parm
  1070.         CMP     AL,'/'                    ;check for "/" parm character
  1071.         JE      Parm_found
  1072.         CMP     AL,' '                    ;check for blanks
  1073.         JNE     Unrecog_parm              ;If other than blank its illegal...
  1074.         LODSB                             ;Keep checking next character
  1075.         LOOP    Parm_Scan
  1076.         RET                               ;finished (parsing parms)
  1077.  
  1078. Parm_Found:                               ;Check if parm is valid
  1079.         DEC     CX                        ;Adjust chars remaining counter
  1080.         JCXZ    Unrecog_parm              ;IF no chars left then parm is invalid
  1081.         LODSB                             ;Get next char
  1082.         DEC     CX                        ;Adjust chars remaining counter
  1083.         AND     AL,5Fh                    ;Capitalize char
  1084.         CMP     AL,'P'                    ;Is it the "Totals wanted" parm?
  1085.         JE      P_parm                    ;T parameter detected
  1086.         CMP     AL,'C'                    ;Is it alternate Check Sum parm?
  1087.         JE      C_parm                    ;C parameter detected..
  1088.         CMP     AL,'O'                    ;Is it "Only chk field compare parm"?
  1089.         JE      O_parm                    ;C parameter detected..
  1090.  
  1091. Unrecog_parm:                             ; an illegal paramter:
  1092.         MOV     DX, offset Bad_Parm_MSG   ;indicate illegal parm was found
  1093.         MOV     AH,09H                    ;DOS display string function
  1094.         INT     21H
  1095. Give_Syntax_and_Quit:
  1096.         CALL    Page_Wait                 ;Force user to acknoledge error
  1097.         MOV     DX, offset Syntax_MSG     ;Give user the correct syntax
  1098.         MOV     AH,09H                    ;DOS display string function
  1099.         INT     21H
  1100.         MOV     AX,4C80h                  ;   terminate with 128 error level
  1101.         INT     21h
  1102.  
  1103. P_parm:
  1104.         MOV     Page_Mode,03h             ;Indicate user wants page mode
  1105.                                           ;Std out already has 3 line header
  1106.                                           ;Originally =FFh to turn page mode off
  1107.         LODSB                             ;Keep checking next character
  1108.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  1109.  
  1110. C_parm:
  1111.         MOV     Changes_Only,'Y'          ;User wants only changes (no add/del)
  1112.         LODSB                             ;Keep checking next character
  1113.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  1114.  
  1115. O_parm:                                   ;"Only" check file size + check fields
  1116. ; IF the /O option is selected, we will patch the length field of two
  1117. ; MOV CX,19 instructions in the COMPARE_FILES subroutine labeled PATCH1 and
  1118. ; PATCH2. The modified routine will then only compare 9 words (the CHECK fields
  1119. ; + file size ) rather than the entire remaining record.
  1120.         MOV     BYTE PTR[PATCH1+1],09     ;Patch length field of MOV CX, instr
  1121.         MOV     BYTE PTR[PATCH2+1],09     ;Patch length field of MOV CX, instr
  1122.         LODSB                             ;Keep checking next character
  1123.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  1124.  
  1125.  
  1126. ;----------------------------------------------------------------;
  1127. ;   File Open Error - put out file open error message + terminate;
  1128. ;   Input:    DX must point to start of filespec                 ;
  1129. ;             DI must point to end of filespec                   ;
  1130. ;----------------------------------------------------------------;
  1131. File_Open_Error:
  1132.         PUSH    DX                        ;Save filename
  1133.         MOV     DX, offset Open_Err_MSG   ;indicate open failed
  1134.         MOV     CX,23                     ;Length of msg is 23 chars
  1135.         MOV     AH,40h                    ;DOS Write func
  1136.         MOV     BX,1                      ;Handle for std output device
  1137.         INT     21h                       ;Write beginning of open error message
  1138.         POP     DX                        ;restore name of file loc to DX
  1139.         SUB     DI,DX                     ;Calc length of filename + CR,LF
  1140.         MOV     CX,DI
  1141.         MOV     AH,40h                    ;DOS Write func
  1142.         INT     21h
  1143.         MOV     DX,OFFSET CRLF_Msg        ;Put out Carriage return + line-feed
  1144.         MOV     AH,09h
  1145.         INT     21h
  1146.         RET
  1147.  
  1148. Put_Out_Initial_MSGs:                     ;Display header and start messages
  1149.         MOV     DX, offset Start_MSG      ;beginning of start message
  1150.         MOV     CX,SM_End-Start_MSG       ;# of chars in start message
  1151.         MOV     AH,40h                    ;DOS Write func
  1152.         MOV     BX,1                      ;Handle for std output device
  1153.         INT     21h                       ;Write Start message
  1154.  
  1155.         MOV     SI,offset Start_Dir       ;Place to store current  directory
  1156.         XOR     DL,DL                     ;Zero DL in order to use default drive
  1157.         MOV     AH,47h                    ;Get current directory (path) func
  1158.         INT     21h
  1159.         CLD                               ;Scan in forward direction
  1160.         MOV     DI,offset Start_Dir       ;Scan dir strng to determine length
  1161.         XOR     AX,AX                     ;Scan for zero termination of dir
  1162.         MOV     CX,64                     ;Scan up to 64 chars of directory
  1163.         REPNE   SCASB                     ;Find 1st zero byte
  1164.         MOV     AX,CRLF
  1165.         STOSW                             ;Terminate dir string with CR LF
  1166.         MOV     DX, offset Start_Dir      ;beginning loc of directory string
  1167.         SUB     DI,SI                     ;Calc length of directory string
  1168.         MOV     CX,DI                     ;Length reg for DOS write function
  1169.         MOV     AH,40h                    ;DOS Write func
  1170.         INT     21h                       ;Write Dir string to finish start msg
  1171.         RET
  1172.  
  1173. ; --------------------------------------------------;
  1174. ; Initialization DATA STORAGE                       ;
  1175. ; --------------------------------------------------;
  1176. Start_MSG     DB  CR,LF,"CFCOMP 1.0 ",BOX," PCDATA TOOLKIT (c) 1990"
  1177.               DB  " Ziff Communications Co.",CR,LF
  1178.               DB  "PC Magazine ",BOX," Wolfgang Stiller - In directory: \"
  1179. SM_End        LABEL  BYTE     ;End of the Start message
  1180. Start_Dir     DB  66  DUP (0)
  1181. Open_ERR_Msg  DB  'CFCOMP unable to open: '
  1182. Empty_Old_Msg DB  'OLDfile assumed empty - execution continues.',CR,LF,'$'
  1183. Bad_Parm_MSG  DB  'Unrecognized parameter detected.',CR,LF,LF,'$'
  1184. NO_FILE_Msg   DB  'You must specify at least OLD and NEW file names to compare.'
  1185.               DB  CR,LF,'$'
  1186. Syntax_Msg    DB  "CFCOMP 1.0 ",BOX," PCDATA TOOLKIT Copyright (c) 1990"
  1187.               DB  " Ziff Communications Co.",CR,LF
  1188.               DB  "PC Magazine ",BOX," Wolfgang Stiller",CR,LF
  1189.               DB  CR,LF,'CFCOMP does a high speed compare of the compressed'
  1190.               DB ' report files produced',CR,LF
  1191.               DB 'by CHKfile.  It displays all changes between the OLD and '
  1192.               DB 'NEW report files.',CR,LF,LF
  1193.               DB 'Syntax is: CFCOMP OLDfile NEWfile  [/C] [/O] [/P]'
  1194.               DB   CR,LF,LF
  1195.               DB  '  OLDfile and NEWfile are files created by CHKFILE.COM.'
  1196.               DB  CR,LF,LF
  1197.               DB  '  "/C"    Display only changed files not additions or '
  1198.               DB  'deletions.',CR,LF
  1199.               DB  '  "/O"    Only use check fields and file size in comparing '
  1200.               DB  'files.'
  1201.               DB  CR,LF
  1202.               DB  '          DOS time and Date stamps are not used for compare.'
  1203.               DB  CR,LF
  1204.               DB  '  "/P"    Pause between pages if changes found.'
  1205.               DB   CR,LF,'$'
  1206. CSEG          EndS
  1207.               END     CFCOMP
  1208.